<?php

namespace unifiedpay\plugins;
use Exception;

require_once dirname(__FILE__)."/vendor/autoload.php";

class Wechat
{
	static public $info = [
		'name' => 'wechat',
		'sort' => 2,
		'link' => 'https://pay.weixin.qq.com/',
		'types' => ['wechat'],
	];

	const GET_AUTH_CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize";
    const GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";

	public $channel;
	private $settings;
	private $notify_url;
	public function __construct() {
		global $_G;
		$this->settings = $this->getConfig();
		$this->notify_url = $_G['siteurl'] . 'api/payment/notify/notify_wechat.php';
	}

	private function getConfig() {
		$settings = \C::t('common_setting')->fetch_setting('unifiedpay_wechat', true);
		if($settings['api_version'] == 1){
			$settings['apikey'] = $settings['apiv3key'];
			$settings['merchantPrivateKeyFilePath'] = DISCUZ_ROOT.$settings['sslkey_path'];
			$settings['merchantCertificateSerial'] = $settings['sslcert_serial'];
			if(!empty($settings['pubkey_id']) && !empty($settings['pubkey_path'])){
				$settings['platformCertificateFilePath'] = DISCUZ_ROOT.$settings['pubkey_path'];
				$settings['platformCertificateSerial'] = $settings['pubkey_id'];
			}else{
				$settings['platformCertificateFilePath'] = DISCUZ_ROOT.$settings['platform_cert_path'];
			}
		}else{
			if($settings['sslcert_path'])
				$settings['sslcert_path'] = DISCUZ_ROOT.$settings['sslcert_path'];
			if($settings['sslkey_path'])
				$settings['sslkey_path'] = DISCUZ_ROOT.$settings['sslkey_path'];
		}
		return $settings;
	}

	public function pay($order) {
		global $_G;
		\C::t('common_payment_order')->update($order['id'], array('channel' => 'wechat', 'plugin' => 'wechat'));
		if(strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger')!==false){
			return $this->wechat_jspay($order);
		}elseif(defined('IN_MOBILE')) {
			if(in_array('3', $this->settings['product'])){
				return $this->wechat_h5pay($order);
			}elseif(in_array('2', $this->settings['product'])){
				$pay_url = $_G['siteurl'] . 'plugin.php?id=unifiedpay:pagepay&out_biz_no='.$order['out_biz_no'].'&pay_channel=wechat';
				return array('code' => 200, 'type' => 'qrcode', 'url' => $pay_url);
			}else{
				return $this->wechat_qrpay($order);
			}
		}else{
			if(in_array('1', $this->settings['product'])){
				return $this->wechat_qrpay($order);
			}else{
				$pay_url = $_G['siteurl'] . 'plugin.php?id=unifiedpay:pagepay&out_biz_no='.$order['out_biz_no'].'&pay_channel=wechat';
				return array('code' => 200, 'type' => 'qrcode', 'url' => $pay_url);
			}
		}
		return array('code' => 500, 'message' => 'Did not open payment');
	}

	//JSAPI支付
	public function pay_jsapi($order, $openid) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
		}
		if($this->settings['api_version'] == 1) {
			$param = [
				'description' => $order['subject'],
				'out_trade_no' => $order['out_biz_no'],
				'notify_url' => $this->notify_url,
				'amount' => [
					'total' => intval($order['amount']),
					'currency' => 'CNY'
				],
				'payer' => [
					'openid' => $openid
				],
				'scene_info' => [
					'payer_client_ip' => $_G['clientip']
				]
			];
			try{
				$client = new \WeChatPay\V3\PaymentService($this->settings);
				$result = $client->jsapiPay($param);
				return array('code' => 200, 'url' => $result);
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		} else {
			$params = [
				'body' => $order['subject'],
				'out_trade_no' => $order['out_biz_no'],
				'total_fee' => $order['amount'],
				'spbill_create_ip' => $_G['clientip'],
				'notify_url' => $this->notify_url,
				'openid' => $openid,
			];
			try{
				$client = new \WeChatPay\PaymentService($this->settings);
				$result = $client->jsapiPay($params);
				return array('code' => 200, 'url' => $result);
			}catch(Exception $e){
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	//APP支付
	public function pay_apppay($order) {
		global $_G;
		if (in_array('4', $this->settings['product'])) {
			return $this->wechat_apppay($order);
		} else {
			$pay_url = $_G['siteurl'] . 'plugin.php?id=unifiedpay:pagepay&out_biz_no='.$order['out_biz_no'].'&pay_channel=wechat';
			return array('code' => 200, 'type' => 'jump', 'url' => $pay_url);
		}
	}

	//小程序支付
	public function pay_miniapp($order, $code) {
		global $_G;

		try{
			$tools = new \WeChatPay\JsApiTool($this->settings['miniappid'], $this->settings['miniappsecret']);
			$openid = $tools->AppGetOpenid($code);
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
		
		$this->settings['appid'] = $this->settings['miniappid'];

		$result = $this->pay_jsapi($order, $openid);
		return $result;
	}

	//公众号支付
	private function wechat_jspay($order) {
		global $_G;

		try{
			$tools = new \WeChatPay\JsApiTool($this->settings['appid'], $this->settings['appsecret']);
			$openid = $tools->GetOpenid();
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}

		$result = $this->pay_jsapi($order, $openid);
		if($result['code'] == 200){
			$result['type'] = 'wxjspay';
			$result['url'] = json_encode($result['url']);
		}
		return $result;
	}

	//扫码支付
	private function wechat_qrpay($order) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
		}
		if($this->settings['api_version'] == 1) {
			$param = [
				'description' => $order['subject'],
				'out_trade_no' => $order['out_biz_no'],
				'notify_url' => $this->notify_url,
				'amount' => [
					'total' => intval($order['amount']),
					'currency' => 'CNY'
				],
				'scene_info' => [
					'payer_client_ip' => $_G['clientip']
				]
			];
			try{
				$client = new \WeChatPay\V3\PaymentService($this->settings);
				$result = $client->nativePay($param);
				return array('code' => 200, 'type' => 'qrcode', 'url' => $result['code_url']);
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		} else {
			$params = [
				'body' => $order['subject'],
				'out_trade_no' => $order['out_biz_no'],
				'total_fee' => $order['amount'],
				'spbill_create_ip' => $_G['clientip'],
				'notify_url' => $this->notify_url,
				'product_id' => '01001',
			];
			try{
				$client = new \WeChatPay\PaymentService($this->settings);
				$result = $client->nativePay($params);
				return array('code' => 200, 'type' => 'qrcode', 'url' => $result['code_url']);
			}catch(Exception $e){
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	//H5支付
	private function wechat_h5pay($order) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
			$_G['setting']['bbname'] = diconv($_G['setting']['bbname'], $_G['charset'], 'UTF-8');
		}
		if($this->settings['api_version'] == 1) {
			$param = [
				'description' => $order['subject'],
				'out_trade_no' => $order['out_biz_no'],
				'notify_url' => $this->notify_url,
				'amount' => [
					'total' => intval($order['amount']),
					'currency' => 'CNY'
				],
				'scene_info' => [
					'payer_client_ip' => $_G['clientip'],
					'h5_info' => [
						'type' => 'Wap',
						'app_name' => $_G['setting']['bbname'],
						'app_url' => $_G['siteurl'],
					],
				]
			];
			try{
				$client = new \WeChatPay\V3\PaymentService($this->settings);
				$result = $client->h5Pay($param);
				$url=$result['h5_url'].'&redirect_url='.urlencode($order['return_url']);
				return array('code' => 200, 'type' => 'jump', 'url' => $url);
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		} else {
			$scene_info = [
				'h5_info' => [
					'type' => 'Wap',
					'wap_url' => $_G['siteurl'],
					'wap_name' => $_G['setting']['bbname']
				]
			];
			$params = [
				'body' => $order['subject'],
				'out_trade_no' => $order['out_biz_no'],
				'total_fee' => $order['amount'],
				'spbill_create_ip' => $_G['clientip'],
				'notify_url' => $this->notify_url,
				'scene_info' => json_encode($scene_info, JSON_UNESCAPED_UNICODE),
			];
			try{
				$client = new \WeChatPay\PaymentService($this->settings);
				$result = $client->h5Pay($params);
				$url=$result['mweb_url'].'&redirect_url='.urlencode($order['return_url']);
				return array('code' => 200, 'type' => 'jump', 'url' => $url);
			}catch(Exception $e){
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	//APP支付
	private function wechat_apppay($order) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
		}
		if($this->settings['api_version'] == 1) {
			$param = [
				'description' => $order['subject'],
				'out_trade_no' => $order['out_biz_no'],
				'notify_url' => $this->notify_url,
				'amount' => [
					'total' => intval($order['amount']),
					'currency' => 'CNY'
				],
				'scene_info' => [
					'payer_client_ip' => $_G['clientip']
				]
			];
			try{
				$client = new \WeChatPay\V3\PaymentService($this->settings);
				$result = $client->appPay($param);
				return array('code' => 200, 'type' => 'sdk', 'url' => $result);
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		} else {
			$params = [
				'body' => $order['subject'],
				'out_trade_no' => $order['out_biz_no'],
				'total_fee' => $order['amount'],
				'spbill_create_ip' => $_G['clientip'],
				'notify_url' => $this->notify_url,
			];
			try{
				$client = new \WeChatPay\PaymentService($this->settings);
				$result = $client->appPay($params);
				return array('code' => 200, 'type' => 'sdk', 'url' => $result);
			}catch(Exception $e){
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	public function status($out_biz_no) {
		global $_G;
		if($this->settings['api_version'] == 1) {
			try{
				$client = new \WeChatPay\V3\PaymentService($this->settings);
				$result = $client->orderQuery(null, $out_biz_no);
				if($result['trade_state'] == 'SUCCESS'){
					$pay_time = strtotime(preg_replace('/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/', '$1-$2-$3 $4:$5:$6', $result['time_end']));
					return array('code' => 200, 'data' => array('trade_no' => $result['transaction_id'], 'payment_time' => $pay_time));
				}else{
					$order_state = array('REFUND'=>'转入退款', 'NOTPAY'=>'未支付', 'CLOSED'=>'已关闭', 'USERPAYING'=>'用户支付中', 'PAYERROR'=>'支付失败', 'ACCEPT'=>'已接收，等待扣款');
					throw new Exception('订单状态：'.($order_state[$result['trade_state']]?$order_state[$result['trade_state']]:$result['trade_state']));
				}
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		} else {
			try{
				$client = new \WeChatPay\PaymentService($this->settings);
				$result = $client->orderQuery(null, $out_biz_no);
				if($result['trade_state'] == 'SUCCESS'){
					$pay_time = strtotime($result['success_time']);
					return array('code' => 200, 'data' => array('trade_no' => $result['transaction_id'], 'payment_time' => $pay_time));
				}else{
					$order_state = array('REFUND'=>'转入退款', 'NOTPAY'=>'未支付', 'CLOSED'=>'已关闭', 'USERPAYING'=>'用户支付中', 'PAYERROR'=>'支付失败', 'ACCEPT'=>'已接收，等待扣款');
					throw new Exception('订单状态：'.($order_state[$result['trade_state']]?$order_state[$result['trade_state']]:$result['trade_state']));
				}
			}catch(Exception $e){
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	public function refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$refund_desc = diconv($refund_desc, $_G['charset'], 'UTF-8');
		}
		if($this->settings['api_version'] == 1) {
			$param = [
				'transaction_id' => $trade_no,
				'out_refund_no' => $refund_no,
				'amount' => [
					'refund' => intval($refund_amount),
					'total' => intval($total_amount),
					'currency' => 'CNY'
				]
			];
			if($refund_desc) $param['reason'] = $refund_desc;
			try{
				$client = new \WeChatPay\V3\PaymentService($this->settings);
				$result = $client->refund($param);
				return array('code' => 200, 'data' => array('refund_time' => time()));
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		} else {
			$params = [
				'transaction_id' => $trade_no,
				'out_refund_no' => $refund_no,
				'total_fee' => $total_amount,
				'refund_fee' => $refund_amount,
			];
			if($refund_desc) $param['refund_desc'] = $refund_desc;
			try{
				$client = new \WeChatPay\PaymentService($this->settings);
				$result = $client->refund($params);
				return array('code' => 200, 'data' => array('refund_time' => time()));
			} catch(Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	public function refund_status($refund_no, $trade_no) {
		global $_G;
		if($this->settings['api_version'] == 1) {
			try{
				$client = new \WeChatPay\V3\PaymentService($this->settings);
				$result = $client->refundQuery($refund_no);
				return array('code' => 200, 'data' => array('refund_time' => time()));
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		} else {
			try{
				$client = new \WeChatPay\PaymentService($this->settings);
				$result = $client->refundQuery($refund_no);
				return array('code' => 200, 'data' => array('refund_time' => time()));
			} catch(Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	public function transfer($transfer_no, $amount, $realname, $account, $title = '', $desc = '') {
		global $_G;
		if(strtoupper($_G['charset'] != 'UTF-8')) {
			$title = diconv($title, $_G['charset'], 'UTF-8');
			$desc = diconv($desc, $_G['charset'], 'UTF-8');
		}

		if($this->settings['api_version'] == 1) {
			try{
				$client = new \WeChatPay\V3\TransferService($this->settings);
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}

			$transfer_detail = [
				'out_detail_no' => $transfer_no,
				'transfer_amount' => intval($amount),
				'transfer_remark' => $desc,
				'openid' => $account,
			];
			if(!empty($payee_real_name)){
				$transfer_detail['user_name'] = $client->rsaEncrypt($payee_real_name);
			}
			$param = [
				'out_batch_no' => $transfer_no,
				'batch_name' => '转账给'.$realname,
				'batch_remark' => date("YmdHis"),
				'total_amount' => intval($amount),
				'total_num' => 1,
				'transfer_detail_list' => [
					$transfer_detail
				],
			];

			try{
				$result = $client->transfer($param);
			} catch (Exception $e) {
				$errorMsg = $e->getMessage();
				if(!strpos($errorMsg, '对应的订单已经存在')){
					if($errorMsg && strtoupper($_G['charset'] != 'UTF-8')) {
						$errorMsg = diconv($errorMsg, 'UTF-8', $_G['charset']);
					}
					return array('code' => 501, 'message' => $errorMsg);
				}
			}
			$batch_id = $result['batch_id'];
			return array('code' => 200, 'data' => array('transfer_time' => time()));
		} else {
			try{
				$client = new \WeChatPay\TransferService($this->settings);
				$result = $client->transfer($transfer_no, $account, $realname, $amount, $desc);
				return array('code' => 200, 'data' => array('transfer_time' => strtotime($result['payment_time'])));
			}catch(Exception $e){
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	public function transfer_status($transfer_no) {
		global $_G;

		if($this->settings['api_version'] == 1) {
			try{
				$client = new \WeChatPay\V3\TransferService($this->settings);
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
			try{
				$result = $client->transferoutdetail($transfer_no, $transfer_no);
				if($result['detail_status'] == 'SUCCESS') {
					return array('code' => 200, 'data' => array('transfer_time' => strtotime($result['update_time'])));
				}elseif($result['detail_status'] == 'PROCESSING') {
					return array('code' => 500, 'message' => '转账中，可稍后重新查询结果');
				}elseif($result['detail_status'] == 'WAIT_PAY') {
					return array('code' => 500, 'message' => '待确认，请在微信支付商家助手进行安全确认');
				}else{
					return array('code' => 500, 'message' => '转账失败['.$result['fail_reason'].']');
				}
			} catch (Exception $e) {
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		} else {
			try{
				$client = new \WeChatPay\TransferService($this->settings);
				$result = $client->transferQuery($transfer_no);
				if($result['status'] == 'SUCCESS') {
					return array('code' => 200, 'data' => array('transfer_time' => strtotime($result['transfer_time'])));
				} else {
					if($result['reason'] && strtoupper($_G['charset'] != 'UTF-8')){
						$result['reason'] = diconv($result['reason'], 'UTF-8', $_G['charset']);
					}
					return array('code' => 500, 'message' => $result['reason']?$result['reason']:$result['status']);
				}
			}catch(Exception $e){
				$errmsg = $e->getMessage();
				if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
					$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
				}
				return array('code' => 501, 'message' => $errmsg);
			}
		}
	}

	public function notify() {
		if($_SERVER['HTTP_WECHATPAY_SIGNATURE']) {
			$isSuccess = true;
			try{
				$client = new \WeChatPay\V3\PaymentService($this->settings);
				$data = $client->notify();
				if($data['trade_state'] == 'SUCCESS') {
					$out_biz_no = $data['out_trade_no'];
					unifiedpay_process_notify($out_biz_no, $data['transaction_id'], $data['payer']['openid']);
				}else{
					$isSuccess = false;
				}
			} catch (Exception $e) {
				$isSuccess = false;
				$errmsg = $e->getMessage();
			}
			$client->replyNotify($isSuccess, $errmsg?$errmsg:'fail');
		}else{
			$isSuccess = true;
			try{
				$client = new \WeChatPay\PaymentService($this->settings);
				$data = $client->notify();
				$out_biz_no = $data['out_trade_no'];
				unifiedpay_process_notify($out_biz_no, $data['transaction_id'], $data['openid']);
			}catch(Exception $e){
				$isSuccess = false;
				$errmsg = $e->getMessage();
			}
			$client->replyNotify($isSuccess, $errmsg?$errmsg:'fail');
		}
	}

	public function oauth() {
		global $_G;
		try{
			$tools = new \WeChatPay\JsApiTool($this->settings['appid'], $this->settings['appsecret']);
			$openid = $tools->GetOpenid();
			return array('code' => 200, 'data' => $openid);
		}catch(Exception $e){
			$errmsg = $e->getMessage();
			if($errmsg && strtoupper($_G['charset'] != 'UTF-8')) {
				$errmsg = diconv($errmsg, 'UTF-8', $_G['charset']);
			}
			return array('code' => 501, 'message' => $errmsg);
		}
	}

	
	public function wechat_authorize($redirect_uri, $state) {
		$param = [
            "appid" => $this->settings['appid'],
            "redirect_uri" => $redirect_uri,
            "response_type" => "code",
            "scope" => "snsapi_base",
            "state" => $state
        ];
        $url = self::GET_AUTH_CODE_URL . '?' . http_build_query($param) . "#wechat_redirect";
        return $url;
	}

	public function wechat_access_token_by_code($code) {
		$param = [
            "appid" => $this->settings['appid'],
            "secret" => $this->settings['appsecret'],
            "code" => $code,
            "grant_type" => "authorization_code"
        ];
		$url = self::GET_ACCESS_TOKEN_URL . '?' . http_build_query($param);
		return $this->wechat_request($url);
	}

	private function wechat_request($api, $data = null) {
		$client = \filesock::open(array(
			'url' => $api,
			'method' => 'POST',
			'post' => $data
		));
		return $client->request();
	}
}